import tensorflow


class BatchNormalization(object):

    def __call__(self, x, mean, var, shift, scale, epsilon):
        return self.tf.nn.batch_normalization(x, mean, var, shift, scale, epsilon)

    def __init__(self, x, shape, axes=[0], epsilon=0.1e-2, tf=tensorflow):
        self.tf = tf
        self.x = x
        self.shape = shape
        self.epsilon = epsilon
        self.axes = axes
        self.scale = self.tf.Variable(self.tf.ones(self.shape))
        self.shift = self.tf.Variable(self.tf.zeros(self.shape))
        self.mean, self.var = self.tf.nn.moments(self.x, self.axes)
        self.y = self.tf.nn.batch_normalization(self.x, self.mean, self.var, self.shift, self.scale, self.epsilon)


class Tanh(object):

    def __call__(self, x):
        return self.tf.nn.tanh(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = tf.nn.tanh(self.x)


class Relu(object):

    def __call__(self, x):
        return self.tf.nn.relu(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = tf.nn.relu(self.x)


class ELU(object):

    def __call__(self, x):
        return self.tf.nn.elu(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = self.tf.nn.elu(self.x)


class LeakyRelu(object):

    def __call__(self, x):
        return self.tf.nn.leaky_relu(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = tf.nn.leaky_relu(self.x)


class Sigmoid(object):

    def __call__(self, x):
        return self.tf.nn.sigmoid(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = tf.nn.sigmoid(self.x)


class Softmax(object):

    def __call__(self, x):
        return self.tf.nn.softmax(x)

    def __init__(self, x, tf=tensorflow):
        self.x = x
        self.tf = tf
        self.y = tf.nn.softmax(self.x)


class Dropout(object):

    def __call__(self, x, keep):
        return self.tf.nn.dropout(x, keep)

    def __init__(self, x, keep, tf=tensorflow):
        self.x = x
        self.keep = keep
        self.tf = tf
        self.y = tf.nn.dropout(self.x, self.keep)


class L2Regularizer(object):

    def __call__(self, x):
        return self.tf.contrib.layers.l2_regularizer(self.delta)(x)

    def __init__(self, x, delta, tf=tensorflow):
        self.tf = tf
        self.x = x
        self.delta = delta
        self.regularizer = self.tf.contrib.layers.l2_regularizer(self.delta)
        self.y = self.regularizer(self.x)
